/*
 *  Copyright (C) 2011 in-somnia
 * 
 *  This file is part of JAAD.
 * 
 *  JAAD is free software; you can redistribute it and/or modify it 
 *  under the terms of the GNU Lesser General Public License as 
 *  published by the Free Software Foundation; either version 3 of the 
 *  License, or (at your option) any later version.
 *
 *  JAAD is distributed in the hope that it will be useful, but WITHOUT 
 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 *  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General 
 *  Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library.
 *  If not, see <http://www.gnu.org/licenses/>.
 */
package net.sourceforge.jaad.mp4.boxes.impl;

import net.sourceforge.jaad.mp4.MP4InputStream;
import java.io.IOException;
import net.sourceforge.jaad.mp4.boxes.FullBox;
import net.sourceforge.jaad.mp4.boxes.Utils;

/**
 * This box specifies the characteristics of a single track. Exactly one Track
 * Header Box is contained in a track. In the absence of an edit list, the
 * presentation of a track starts at the beginning of the overall presentation.
 * An empty edit is used to offset the start time of a track.
 * If in a presentation all tracks have neither trackInMovie nor trackInPreview
 * set, then all tracks shall be treated as if both flags were set on all
 * tracks. Hint tracks should not have the track header flags set, so that they
 * are ignored for local playback and preview.
 * The width and height in the track header are measured on a notional 'square'
 * (uniform) grid. Track video data is normalized to these dimensions
 * (logically) before any transformation or placement caused by a layup or
 * composition system. Track (and movie) matrices, if used, also operate in this
 * uniformly-scaled space.
 * @author in-somnia
 */
public class TrackHeaderBox extends FullBox {

	private boolean enabled, inMovie, inPreview;
	private long creationTime, modificationTime, duration;
	private int trackID, layer, alternateGroup;
	private double volume, width, height;
	private double[] matrix;

	public TrackHeaderBox() {
		super("Track Header Box");
		matrix = new double[9];
	}

	@Override
	public void decode(MP4InputStream in) throws IOException {
		super.decode(in);

		enabled = (flags&1)==1;
		inMovie = (flags&2)==2;
		inPreview = (flags&4)==4;

		final int len = (version==1) ? 8 : 4;
		creationTime = in.readBytes(len);
		modificationTime = in.readBytes(len);
		trackID = (int) in.readBytes(4);
		in.skipBytes(4); //reserved
		duration = Utils.detectUndetermined(in.readBytes(len));

		in.skipBytes(8); //reserved

		layer = (int) in.readBytes(2);
		alternateGroup = (int) in.readBytes(2);
		volume = in.readFixedPoint(8, 8);

		in.skipBytes(2); //reserved

		for(int i = 0; i<9; i++) {
			if(i<6) matrix[i] = in.readFixedPoint(16, 16);
			else matrix[i] = in.readFixedPoint(2, 30);
		}

		width = in.readFixedPoint(16, 16);
		height = in.readFixedPoint(16, 16);
	}

	/**
	 * A flag indicating that the track is enabled. A disabled track is treated
	 * as if it were not present.
	 * @return true if the track is enabled
	 */
	public boolean isTrackEnabled() {
		return enabled;
	}

	/**
	 * A flag indicating that the track is used in the presentation.
	 * @return true if the track is used
	 */
	public boolean isTrackInMovie() {
		return inMovie;
	}

	/**
	 * A flag indicating that the track is used when previewing the
	 * presentation.
	 * @return true if the track is used in previews
	 */
	public boolean isTrackInPreview() {
		return inPreview;
	}

	/**
	 * The creation time is an integer that declares the creation time of the
	 * presentation in seconds since midnight, Jan. 1, 1904, in UTC time.
	 * @return the creation time
	 */
	public long getCreationTime() {
		return creationTime;
	}

	/**
	 * The modification time is an integer that declares the most recent time
	 * the presentation was modified in seconds since midnight, Jan. 1, 1904,
	 * in UTC time.
	 */
	public long getModificationTime() {
		return modificationTime;
	}

	/**
	 * The track ID is an integer that uniquely identifies this track over the
	 * entire life-time of this presentation. Track IDs are never re-used and
	 * cannot be zero.
	 * @return the track's ID
	 */
	public int getTrackID() {
		return trackID;
	}

	/**
	 * The duration is an integer that indicates the duration of this track (in 
	 * the timescale indicated in the Movie Header Box). The value of this field
	 * is equal to the sum of the durations of all of the track's edits. If 
	 * there is no edit list, then the duration is the sum of the sample 
	 * durations, converted into the timescale in the Movie Header Box. If the 
	 * duration of this track cannot be determined then this value is -1.
	 * @return the duration this track
	 */
	public long getDuration() {
		return duration;
	}

	/**
	 * The layer specifies the front-to-back ordering of video tracks; tracks
	 * with lower numbers are closer to the viewer. 0 is the normal value, and
	 * -1 would be in front of track 0, and so on.
	 * @return the layer
	 */
	public int getLayer() {
		return layer;
	}

	/**
	 * The alternate group is an integer that specifies a group or collection
	 * of tracks. If this field is 0 there is no information on possible
	 * relations to other tracks. If this field is not 0, it should be the same
	 * for tracks that contain alternate data for one another and different for
	 * tracks belonging to different such groups. Only one track within an
	 * alternate group should be played or streamed at any one time, and must be
	 * distinguishable from other tracks in the group via attributes such as
	 * bitrate, codec, language, packet size etc. A group may have only one
	 * member.
	 * @return the alternate group
	 */
	public int getAlternateGroup() {
		return alternateGroup;
	}

	/**
	 * The volume is a floating point number that indicates the preferred
	 * playback volume: 0.0 is mute, 1.0 is normal volume.
	 * @return the volume
	 */
	public double getVolume() {
		return volume;
	}

	/**
	 * The width specifies the track's visual presentation width as a floating
	 * point values. This needs not be the same as the pixel width of the
	 * images, which is documented in the sample description(s); all images in
	 * the sequence are scaled to this width, before any overall transformation
	 * of the track represented by the matrix. The pixel dimensions of the
	 * images are the default values. 
	 * @return the image width
	 */
	public double getWidth() {
		return width;
	}

	/**
	 * The height specifies the track's visual presentation height as a floating
	 * point value. This needs not be the same as the pixel height of the
	 * images, which is documented in the sample description(s); all images in
	 * the sequence are scaled to this height, before any overall transformation
	 * of the track represented by the matrix. The pixel dimensions of the
	 * images are the default values.
	 * @return the image height
	 */
	public double getHeight() {
		return height;
	}

	public double[] getMatrix() {
		return matrix;
	}
}
